# __HEADER__

"""XXX

- Consider disabling syslog.
"""

import os
import shutil
import signal
import subprocess
import time
import unittest

import ldap
import oldap.cache
from oldap.model import Model

class posixAccount(Model):

    base_dn = 'dc=example,dc=com'
    objectClass = ('posixAccount', 'inetOrgPerson')
    rdn_attributes = ('uid',)

class multiRdn(Model):

    base_dn = 'dc=example,dc=com'
    objectClass = ('posixAccount', 'inetOrgPerson')
    rdn_attributes = ('uid', 'uidNumber')

class organizationalUnit(Model):

    base_dn = 'dc=example,dc=com'
    objectClass = ('organizationalUnit',)
    rdn_attributes = ('ou',)

class inetOrgPerson(Model):

    base_dn = 'dc=example,dc=com'
    objectClass = ('inetOrgPerson',)
    rdn_attributes = ('cn',)


class Base:

    process = None

    def startup(self):
        if os.path.exists('openldap/data'):
            shutil.rmtree('openldap/data')
        os.mkdir('openldap/data')

        def args(n):
            # XXX: shlex
            return n.split(' ')

        subprocess.check_call(args('slapadd -f ./openldap/slapd.conf -l ./openldap/init.ldif'))

        oldap.cache.initialize('ldap://127.0.0.1:9389/', 'cn=Manager,dc=example,dc=com', 'secret')
        self.process = subprocess.Popen(args('/usr/local/libexec/slapd '
            '-d 0 -f ./openldap/slapd.conf -h ldap://127.0.0.1:9389/'))
        # Wait for it to start up.
        for unused in xrange(10):
            try:
                unused = oldap.cache.get_connection()
            except ldap.LDAPError:
                time.sleep(0.5)
            else:
                break
        else:
            self.shutdown()
            raise AssertionError('Couldn\'t contact slapd process.')

    def shutdown(self):
        if self.process is not None:
            self.process.send_signal(signal.SIGTERM)
            self.process.wait()
            self.process = None

class BaseTest(Base, unittest.TestCase):

    def setUp(self):
        self.startup()

    def tearDown(self):
        self.shutdown()

    def assertEqualSorted(self, x, y):
        self.assertEqual(sorted(x), sorted(y))

    def assertGroupMembers(self, group, members):
        self.assertEqual(sorted(group.memberUid), sorted(members))

    def new_account(self, uid, number, cls, **kwargs):
        return cls(uid=[uid], cn=['User'],
                gidNumber=number, uidNumber=number, sn=['Doe'], homeDirectory='/home/%s' % (uid,),
                **kwargs)

    def assertReferenceEquals(self, reference, items):
        """Check that a reference contains the correct items.

        The order of the items does not matter.

        :Paramters:
            - `reference`: The ReferenceFilter to check.
            - `items`: List of objects the reference should contain.
        """
        r = reference.all()[:]
        r.sort(key=lambda x:x.rdn)
        items.sort(key=lambda x:x.rdn)
        self.assertEqual(r, items)


def interactive():
    import code
    import oldap.cache
    t = Base()
    local = globals().copy()
    t.startup()
    local['conn'] = oldap.cache.get_connection()
    try:
        code.interact(local=local)
    finally:
        t.shutdown()

if __name__ == '__main__':
    interactive()
